# Copyright (c) 2019 Presto Labs Pte. Ltd.
# Author: jaewon

import datetime
import os

from coin.base.datetime_util import to_datetime
from coin.strategy.marketsim.core import spec_pb2
from experimental.prophet.craps.universe import universe_btc

from coin.strategy.marketsim import result_util
from coin.strategy.marketsim.strategy.pass_unhedge import PassUnhedgeSimStrategy

run_id = None
sim_out_dir = None


def prepare(args, ref_ts, **kwargs):
  global run_id, sim_out_dir
  run_id = kwargs.get('run_id', None)
  sim_out_dir = kwargs.get('sim_out_dir', None)


def get_machine():
  return 'feed-01.ap-northeast-1.aws'


def get_time_ranges():
  ranges = []
  cur_dt = datetime.datetime(2019, 7, 20, 0, 0, 0)
  end_dt = datetime.datetime(2019, 8, 13, 0, 0, 0)
  while cur_dt < end_dt:
    ranges.append((cur_dt, cur_dt + datetime.timedelta(hours=24)))
    cur_dt += datetime.timedelta(hours=24)
  return ranges


def linear_sell_edge(edge, close_edge, max_pos, pos):
  if pos <= 0.:
    return edge
  elif pos >= max_pos:
    return close_edge
  else:
    p = (pos / float(max_pos))
    return (p * close_edge + (1 - p) * edge)


def linear_buy_edge(edge, close_edge, max_pos, pos):
  if pos >= 0.:
    return edge
  elif pos <= -max_pos:
    return close_edge
  else:
    p = (-pos / float(max_pos))
    return (p * close_edge + (1 - p) * edge)


def get_strategy(from_ts, to_ts):
  sim_spec = spec_pb2.MarketSimSpecProto(
      latency=1 * 10**9,  # 1 sec,
      feed_cut_time_allowance=300 * 10**9,  # 5 min
      clear_on_feed_cut=True)

  machine = get_machine()

  symbol_infos = universe_btc(from_ts)
  fxbtcjpy = symbol_infos[0]
  xbtusd = symbol_infos[1]
  btcusd_quarter = symbol_infos[6]
  btcusd_next_week = symbol_infos[7]
  btcusd_this_week = symbol_infos[8]

  pass_symbol_info = fxbtcjpy
  pass_product_sim_spec = spec_pb2.ProductSpecProto(symbol=str(fxbtcjpy.product),
                                                    settlement_currency='JPY',
                                                    inverse=False,
                                                    maker_fee=0.,
                                                    taker_fee=0.,
                                                    support_post_only=False,
                                                    fastfeed_machine=machine,
                                                    fastfeed_sub_req=fxbtcjpy.sub_req)

  ref_symbol_info = xbtusd  # btcusd_quarter

  strategy_list = []

  for basis_window in ['02m', '05m', '20m', '60m']:
    for edge_bp in [3, 5, 10, 15]:
      for close_edge_bp in [edge_bp]:  # sorted(set([-1, 5, edge_bp])):
        for stack in [5, 10, 20]:
          lot_size = 1. / stack

          name = 'fxbtcjpy.%s.%s.%02dbp.%02dbp.%02dstack.%s' % (
              ref_symbol_info.nickname,
              basis_window,
              edge_bp,
              close_edge_bp,
              stack,
              to_datetime(from_ts).strftime('%Y%m%d'))

          params = {
              'pass_product_sim_spec': pass_product_sim_spec,
              'pass_symbol_info': pass_symbol_info,
              'ref_symbol_info': ref_symbol_info,
              'machine': machine,
              'basis_window': basis_window,
              'ref_price_multiplier': 108.,
              'tick': 1.,
              'edge': edge_bp / 10000.,
              'lot_size': lot_size,
              'min_pos': -lot_size * stack,
              'max_pos': lot_size * stack,
              'min_fire_period': 8 * (10**9),
              'post_only': False,
              'sim_spec': sim_spec,
              'name': name,
          }
          strategy = PassUnhedgeSimStrategy(**params)
          strategy_list.append(strategy)

  return strategy_list


def get_strategy_result(strategy):
  if run_id is not None and sim_out_dir is not None:
    out_dir = os.path.join(sim_out_dir, 'run-' + run_id)
    os.makedirs(out_dir, exist_ok=True)
    out_path = os.path.join(out_dir, strategy.name + '.gz')
    strategy.sim.dump_sim_result(out_path, tag=strategy.name)

  sim_stat = strategy.get_sim_stat()
  sim_stat.tag = strategy.name
  return sim_stat


def aggregate_result(results):
  result_util.aggregate_sim_stat(results, show_stat_only=False)
  # for res in results:
  #  print(res)
  # return result_util.aggregate_sim_result(results)
